%{
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

static int tabstop = 2;
static int indent = 0;
static int pp_indent = 0;
static int par_indent = 0;
static int singlestmt = 0; /* TODO: handle "if (__) \n __;" statements */

static void printspaces(int);
%}

%s COMMENT STRINGLITERAL ESCAPED NI PP PP_ARG STMT

NL	("\n"|"\r\n")

%%

<INITIAL>^[ \t]*#[ \t]* { /* handle preprocessor directives */
                          putchar('#');
                          BEGIN PP;
                        }
<PP>ifndef |
<PP>ifdef |
<PP>if {
         int i;
         for (i = 0; i < pp_indent; i++)
           fputc(' ', stdout);
         fputs(yytext, stdout);
         pp_indent += 1;
         BEGIN PP_ARG;
       }
<PP>elif |
<PP>else {
           int i;
           for (i = 0; i < pp_indent - 1; i++)
             fputc(' ', stdout);
           fputs(yytext, stdout);
           BEGIN PP_ARG;
         }
<PP>endif |
<PP>fi {
         int i;
         pp_indent--;
         for (i = 0; i < pp_indent; i++)
           fputc(' ', stdout);
         fputs(yytext, stdout);
         BEGIN PP_ARG;
       }
<PP>[a-z]+ { /* command */
             int i;
             for (i = 0; i < pp_indent; i++)
               fputc(' ', stdout);
             fputs(yytext, stdout);
             BEGIN PP_ARG;
           }

<PP_ARG>"\\"{NL} { ECHO; }
<PP_ARG>{NL} { ECHO; BEGIN 0; }

<INITIAL>[ \t\r\n]*"{"[ \t\v\f]* { /* OP - curly brace */
                         int i = 0;
                         puts("");
                         printspaces(tabstop * indent + tabstop * par_indent * 2);
                         fputc('{', stdout);
                         indent++;
                         /*
                         if (strrchr(yytext, '\n'))
                           puts("");
                         printspaces(tabstop * indent + tabstop * par_indent * 2);
                         */
                       }
<INITIAL>{NL}[ \t]*"}" { /* CL - curly brace */
                         int i = 0;
                         indent--;
                         puts("");
                         while (yytext[i] && (yytext[i] == '\r' || yytext[i] == '\n'))
                           i++;
                         printspaces(tabstop * indent + tabstop * par_indent * 2);
                         fputc('}', stdout);
                       }

<INITIAL>"(" {
               ECHO;
               par_indent++;
             }
<INITIAL>")" {
               ECHO;
               par_indent--;
             }

 /* state, that eats preceeding whitespace and replaces it with what we need */
<INITIAL>{NL}[ \t\f\v]*$ {
                           puts("");
                         }
<INITIAL>{NL}[ \t]* {
                      int i = 0;
                      puts("");
                      while (yytext[i] && (yytext[i] == '\r' || yytext[i] == '\n'))
                        i++;
                      printspaces(tabstop * indent + tabstop * par_indent * 2);
                    }

<INITIAL>"\\" { ECHO; BEGIN ESCAPED; }
<ESCAPED>(.|{NL}) { ECHO; BEGIN 0; }

<INITIAL>"\"" { ECHO; BEGIN STRINGLITERAL; }
<STRINGLITERAL>"\\"(.|{NL}) { ECHO; }
<STRINGLITERAL>"\"" { ECHO; BEGIN 0; }
<STRINGLITERAL>(.|{NL}) { ECHO; }

<INITIAL>"/*" { ECHO; BEGIN COMMENT; }
<COMMENT>(.|"\n"|"\r\n") { ECHO; }
<COMMENT>"*/" { ECHO; BEGIN 0; }

 /*<INITIAL>(.|{NL}) {} /* silence the rest of input */
 /*<INITIAL>{NL} {} /* kill stray NLs */

%%

int yywrap(void) { return 1; }

int main(int argc, char **argv) {
	if (argc == 2)
		tabstop = atoi(argv[1]);
	yylex();
	return 0;
}

void printspaces(int n) {
	int i;

	for (i = 0; i < n; i++) {
		putchar(' ');
	}
}
